package com.media.service.impl;


import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.common.context.UserContextHolder;
import com.common.exception.GlobalException;
import com.common.exception.media.MediaFileUploadException;
import com.common.rabbitmq.producer.core.UserProducer;
import com.media.domain.pojo.Media;
import com.media.domain.pojo.Users;
import com.media.domain.vo.MediaVo;
import com.media.feign.UserFeignClient;
import com.media.mapper.MediaMapper;
import com.media.service.IMediaService;
import com.media_server.pojo.MediaDetail;
import com.media_server.service.impl.DefaultMediaMinioServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;


/**
 * <p>
 * 媒体表 服务实现类
 * </p>
 *
 * @author 小杰大人
 * @since 2025-01-15
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class MediaServiceImpl extends ServiceImpl<MediaMapper, Media> implements IMediaService {
    private final DefaultMediaMinioServiceImpl defaultMediaMinioServiceImpl;

    @Resource(name = "myTransactionTemplate")
    TransactionTemplate transactionTemplate;
    private final UserFeignClient userFeignClient;
    private final UserProducer userProducer;



    @Override
    public MediaVo uploadImage(MultipartFile file) {
        // 获取文件大小
        long size = file.getSize();
        if((size / (1024.0 * 1024.0)) > 5){
            throw new MediaFileUploadException("文件过大，请上传5M以下的文件");
        }
        return uploadVideo(file);
    }

    @Override
    public MediaVo uploadVideo(MultipartFile file) {
        Media media = upload(file);
        return new MediaVo(media.getId(), media.getUrl());
    }

    @Override
    public MediaVo uploadAvatar(MultipartFile file) {
        // 获取文件大小
        long size = file.getSize();
        if((size / (1024.0 * 1024.0)) > 2){
            throw new MediaFileUploadException("文件过大，请上传2M以下的文件");
        }
        Media media = upload(file);
        // 更新操作人的头像
        Users users = userFeignClient.querySelectByUniqueIdentification(UserContextHolder.getContext().getUsersId()).getData();
        Long mediaId = users.getMediaId();  // 原始头像id
        if (mediaId != null){
            // 调用删除方法 删除数据库信息与头像文件
            transactionTemplate.executeWithoutResult(status -> this.deleteById(mediaId));
        }
        // 异步 更新用户头像
        userProducer.send("user.update.avatar", new MediaVo(media.getId(),media.getUrl()));
        // 构建返回对象
        MediaVo mediaVo = new MediaVo();
        mediaVo.setId(media.getId());
        mediaVo.setUrl(media.getUrl());
        return mediaVo;
    }

    @Override
    public Map<Long, Media> getMediaByIds(List<Long> ids) {
        if (ids == null || ids.isEmpty()){
            return MapUtil.empty();
        }
        return this.listByIds(ids).stream().collect(Collectors.toMap(Media::getId, value -> value));
    }

    @Override
    public void deleteById(Long id) {
        // 得到待删除的媒体信息
        Media media = this.getById(id);
        if (media == null){
            return;
        }
        transactionTemplate.execute(status -> {
            defaultMediaMinioServiceImpl.delete(media.getBucket(),media.getFilePath());
            return this.removeById(id);
        });
    }

    @Override
    public void deleteByIds(List<Long> ids) {
        if (ids == null || ids.isEmpty()){
            return;
        }
        List<Media> media = this.listByIds(ids);
        transactionTemplate.executeWithoutResult(status -> {
            boolean removeByIds = this.removeByIds(ids);
            if (removeByIds){
                // 删除 minio 中的文件数据
                CompletableFuture.runAsync(() -> media.forEach(item -> defaultMediaMinioServiceImpl.delete(item.getBucket(),item.getFilePath())));
            }
        });

    }

    private Media upload(MultipartFile file){
        // 获取文件名
        String originalFilename = file.getOriginalFilename();
        // 获取文件流
        InputStream inputStream;
        try {
            inputStream = file.getInputStream();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        // 获取文件大小
        long size = file.getSize();
        // 文件信息对象
        MediaDetail mediaDetail;
        // 文件大于1G则采用分片上传
        if (size / (1024 * 1024) > 1024) {
            log.debug("文件过大 采用分片上传模式");
            mediaDetail = defaultMediaMinioServiceImpl.multipartUpload(originalFilename , inputStream);
        }else {
            mediaDetail = defaultMediaMinioServiceImpl.upload(originalFilename , inputStream);
        }
        if (mediaDetail == null){    // 上传失败
            throw new GlobalException("上传失败");
        }
        // 将文件信息存入数据库
        Media media = new Media();
        // 设置文件所在的存储桶名称
        media.setBucket(mediaDetail.getBucket());
        // 设置文件名
        media.setFileName(mediaDetail.getOriginFileName());
        // 设置文件的MD5哈希值，用于唯一标识文件
        media.setFileMd5(mediaDetail.getMd5());
        // 将文件大小转换为字符串后设置，因为Media类中的 fileSize 字段是字符串类型
        media.setFileSize(Long.toString(size));
        // 设置文件的类型，例如图像、视频等
        media.setFileType(mediaDetail.getContentType());
        // 设置文件的原始名称，即上传前的名称
        media.setOriginName(originalFilename);
        // 设置文件的存储路径URL
        media.setFilePath(mediaDetail.getObjectName());
        // 设置文件的访问URL，用于在系统中查找文件
        media.setUrl(mediaDetail.getUrl());
        // 获取视频的时长
        media.setDuration(mediaDetail.getDuration());
        try {
            transactionTemplate.execute(status -> save(media));
        } catch (Exception e) {
            defaultMediaMinioServiceImpl.delete(media.getBucket(),media.getFilePath());
            throw e;
        }
        return media;

    }
}
